package cn.bby.jtk.mp.util;

import cn.bby.jtk.bean.copier.FastBeanCopier;
import cn.bby.jtk.bean.util.FastBeanUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.Query;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.toolkit.reflect.GenericTypeUtils;
import com.baomidou.mybatisplus.extension.conditions.ChainWrapper;

import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * @author ben
 * @version 1.0
 * @date 2025/07/11
 * @since 17
 */
public class QueryWrapperUtil {
    private static final Map<Class<?>, Class<?>> mapperEntityCache = new ConcurrentHashMap<>();

    /**
     * 查询并转换成指定对象
     * @param chainWrapper 查询条件
     * @param resultClass 返回对象类型
     * @param <E> 实体类型
     * @param <R> 返回对象类型
     */
    public static <E,R> List<R> queryBean(ChainWrapper<E> chainWrapper, Class<R> resultClass, String ...extraSelect){
        return queryBean(chainWrapper.getWrapper(), chainWrapper.getBaseMapper(), resultClass, extraSelect);
    }

    /**
     * 查询并转换成指定对象
     * @param wrapper 查询条件
     * @param baseMapper mapper
     * @param resultClass 返回对象类型
     * @param <E> 实体类型
     * @param <R> 返回对象类型
     */
    public static <E,R> List<R> queryBean(Wrapper<E> wrapper, BaseMapper<E> baseMapper, Class<R> resultClass, String ...extraSelect){
        Class<E> entityClass = getEntityClass(baseMapper);
        FastBeanCopier<E, R> beanCopier = FastBeanCopier.create(entityClass, resultClass, false);
        if (StrUtil.isBlank(wrapper.getSqlSelect()) && wrapper instanceof Query<?,?,?> query) {
            Set<String> fieldSet = Arrays.stream(ReflectUtil.getFields(resultClass)).map(Field::getName)
                    .collect(Collectors.toSet());
            if (extraSelect != null && extraSelect.length > 0) {
                fieldSet.addAll(Arrays.asList(extraSelect));
            }
            query.select(tableFieldInfo -> fieldSet.contains(tableFieldInfo.getProperty()));
        }
        return baseMapper.selectList(wrapper).stream().map(e -> {
            R r = FastBeanUtil.copyProperties(e, resultClass);
            beanCopier.copy(e, r, null);
            return r;
        }).collect(Collectors.toList());
    }

    @SuppressWarnings("unchecked")
    private static <E> Class<E> getEntityClass(BaseMapper<E> baseMapper) {
        return (Class<E>) mapperEntityCache.computeIfAbsent(baseMapper.getClass(), (k) -> {
            Class<?>[] classes = GenericTypeUtils.resolveTypeArguments(k, BaseMapper.class);
            return classes[0];
        });
    }
}
